%{
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define YYSTYPE double
extern void yyerror(char const *s);

int Max_top = 100;
int Max_length_of_string = 100;
int min_top = 0;
struct _stack{
    int top;
    char data[100][100];
};

typedef struct _stack _stack;
void init_stack(_stack *stack){
    int i;
    stack->top = min_top-1;
    for(i = 0; i < Max_top; i++)
        memset(stack->data[i], 0, sizeof(char) * 100);
}
int push_to_stack(_stack *stack, char *InItem){
    stack->top++;
    if(stack->top > Max_top-1)
        return 1;
    sprintf(stack->data[stack->top], "%s", InItem);
    return 0;
}
int pop_from_stack(_stack *stack, char *OutItem){
    if(stack->top < min_top)
        return 1;
    sprintf(OutItem, "%s", stack->data[stack->top--]);
    return 0;
}
_stack arith;
_stack var;
_stack assign;
_stack logic_stack;
char tmp1[100];
char tmp2[100];
char tmp3[100];

%}
%token NUMBER DIST POSITION DIRECTION DISTANCE CONSTANT IDENTIFIER
%token NL  OR_OP AND_OP EQ_OP NE_OP GE_OP LE_OP
%left OR_OP
%left AND_OP
%left EQ_OP NE_OP
%left '>' '<' GE_OP LE_OP
%left '+' '-'
%left '*' '/' '%'
%right UMINUS

%%

lines : lines expr NL {   memset(tmp1, 0, sizeof(char)*100);
			    pop_from_stack(&logic_stack, tmp1);
			    printf("%s\n", tmp1); }
    | lines NL
    |
    ;
expr : assignment_expr
       |  logic_expr
    ;

assignment_expr : variable '=' arithmetc_expr	 {  memset(tmp1, 0, sizeof(char)*100);
		  		memset(tmp2, 0, sizeof(char)*100);
				memset(tmp3, 0, sizeof(char)*100);
				pop_from_stack(&var, tmp1);
				pop_from_stack(&arith, tmp2);
				sprintf(tmp3, "%s = %s", tmp1, tmp2);
				push_to_stack(&assign, tmp3);
		  }


logic_expr: logic_expr OR_OP logic_expr	{   memset(tmp1, 0, sizeof(char)*100);
                                            memset(tmp2, 0, sizeof(char)*100);
                                            memset(tmp3, 0, sizeof(char)*100);
                                            pop_from_stack(&logic_stack, tmp2);
                                            pop_from_stack(&logic_stack, tmp1);
                                            sprintf(tmp3, "%s || %s", tmp1, tmp2);
                                            push_to_stack(&logic_stack, tmp3);
					}
        | logic_expr AND_OP logic_expr	{   memset(tmp1, 0, sizeof(char)*100);
                                            memset(tmp2, 0, sizeof(char)*100);
                                            memset(tmp3, 0, sizeof(char)*100);
                                            pop_from_stack(&logic_stack, tmp2);
                                            pop_from_stack(&logic_stack, tmp1);
                                            sprintf(tmp3, "%s && %s", tmp1, tmp2);
                                            push_to_stack(&logic_stack, tmp3);
					}
	| logic_expr EQ_OP logic_expr	{   memset(tmp1, 0, sizeof(char)*100);
                                            memset(tmp2, 0, sizeof(char)*100);
                                            memset(tmp3, 0, sizeof(char)*100);
                                            pop_from_stack(&logic_stack, tmp2);
                                            pop_from_stack(&logic_stack, tmp1);
                                            sprintf(tmp3, "%s == %s", tmp1, tmp2);
                                            push_to_stack(&logic_stack, tmp3);
					}
	| logic_expr NE_OP logic_expr	{       memset(tmp1, 0, sizeof(char)*100);
						memset(tmp2, 0, sizeof(char)*100);
						memset(tmp3, 0, sizeof(char)*100);
						pop_from_stack(&logic_stack, tmp2);
						pop_from_stack(&logic_stack, tmp1);
						sprintf(tmp3, "%s != %s", tmp1, tmp2);
						push_to_stack(&logic_stack, tmp3);
					}
	| logic_expr '>' logic_expr {       memset(tmp1, 0, sizeof(char)*100);
                                            memset(tmp2, 0, sizeof(char)*100);
                                            memset(tmp3, 0, sizeof(char)*100);
                                            pop_from_stack(&logic_stack, tmp2);
                                            pop_from_stack(&logic_stack, tmp1);
                                            sprintf(tmp3, "%s > %s", tmp1, tmp2);
                                            push_to_stack(&logic_stack, tmp3);
                                    }
	| logic_expr '<' logic_expr {       memset(tmp1, 0, sizeof(char)*100);
                                            memset(tmp2, 0, sizeof(char)*100);
                                            memset(tmp3, 0, sizeof(char)*100);
                                            pop_from_stack(&logic_stack, tmp2);
                                            pop_from_stack(&logic_stack, tmp1);
                                            sprintf(tmp3, "%s < %s", tmp1, tmp2);
                                            push_to_stack(&logic_stack, tmp3);
                                    } 
	| logic_expr GE_OP logic_expr	{       memset(tmp1, 0, sizeof(char)*100);
			                        memset(tmp2, 0, sizeof(char)*100);
						memset(tmp3, 0, sizeof(char)*100);
						pop_from_stack(&logic_stack, tmp2);
						pop_from_stack(&logic_stack, tmp1);
						sprintf(tmp3, "%s >= %s", tmp1, tmp2);
						push_to_stack(&logic_stack, tmp3);
					}

	| logic_expr LE_OP logic_expr	{       memset(tmp1, 0, sizeof(char)*100);
			                        memset(tmp2, 0, sizeof(char)*100);
						memset(tmp3, 0, sizeof(char)*100);
						pop_from_stack(&logic_stack, tmp2);
						pop_from_stack(&logic_stack, tmp1);
						sprintf(tmp3, "%s <= %s", tmp1, tmp2);
						push_to_stack(&logic_stack, tmp3);
					}

    	| '(' logic_expr ')'	{   memset(tmp1, 0, sizeof(char)*100);
	                            memset(tmp3, 0, sizeof(char)*100);
			            pop_from_stack(&logic_stack, tmp1);
				    sprintf(tmp3, "( %s )", tmp1);
				    push_to_stack(&logic_stack, tmp3);
				}

	| '!' logic_expr %prec UMINUS	{   memset(tmp1, 0, sizeof(char)*100);
	                                    memset(tmp3, 0, sizeof(char)*100);
					    pop_from_stack(&logic_stack, tmp1);
					    sprintf(tmp3, " !%s ", tmp1);
					    push_to_stack(&logic_stack, tmp3);
					}

	| CONSTANT  {	memset(tmp3, 0, sizeof(char)*100);
			sprintf(tmp3, "%s", yylval);
			push_to_stack(&logic_stack, tmp3);
		    }
	| variable  {   memset(tmp1, 0, sizeof(char)*100);
                        memset(tmp3, 0, sizeof(char)*100);
                        pop_from_stack(&var, tmp1);
                        sprintf(tmp3, "%s", tmp1);
                        push_to_stack(&logic_stack, tmp3);
                    }
	;


arithmetc_expr : arithmetc_expr '+' arithmetc_expr	{   memset(tmp1, 0, sizeof(char)*100);
			    memset(tmp2, 0, sizeof(char)*100);
			    memset(tmp3, 0, sizeof(char)*100);
			    pop_from_stack(&arith, tmp2);
			    pop_from_stack(&arith, tmp1);
			    sprintf(tmp3, "%s + %s", tmp1, tmp2);
			    push_to_stack(&arith, tmp3); 
			}
    | arithmetc_expr '-' arithmetc_expr {	memset(tmp1, 0, sizeof(char)*100);
                        memset(tmp2, 0, sizeof(char)*100);
                        memset(tmp3, 0, sizeof(char)*100);
			pop_from_stack(&arith, tmp2);
                        pop_from_stack(&arith, tmp1);
                        sprintf(tmp3, "%s - %s", tmp1, tmp2);
                        push_to_stack(&arith, tmp3);
		    }
    | arithmetc_expr '*' arithmetc_expr {	memset(tmp1, 0, sizeof(char)*100);
                        memset(tmp2, 0, sizeof(char)*100);
                        memset(tmp3, 0, sizeof(char)*100);
			pop_from_stack(&arith, tmp2);
                        pop_from_stack(&arith, tmp1);
                        sprintf(tmp3, "%s * %s", tmp1, tmp2);
                        push_to_stack(&arith, tmp3); 
		    }
    | arithmetc_expr '/' arithmetc_expr {	memset(tmp1, 0, sizeof(char)*100);
                        memset(tmp2, 0, sizeof(char)*100);
                        memset(tmp3, 0, sizeof(char)*100);
			pop_from_stack(&arith, tmp2);
			pop_from_stack(&arith, tmp1);
			sprintf(tmp3, "%s / %s", tmp1, tmp2);
			push_to_stack(&arith, tmp3);
		    }
    | arithmetc_expr '%' arithmetc_expr {	memset(tmp1, 0, sizeof(char)*100);
                        memset(tmp2, 0, sizeof(char)*100);
                        memset(tmp3, 0, sizeof(char)*100);
			pop_from_stack(&arith, tmp2);
			pop_from_stack(&arith, tmp1);
			sprintf(tmp3, "%s %s %s", tmp1,"%" ,tmp2);
			push_to_stack(&arith, tmp3);
		    }
    | '(' arithmetc_expr ')'  {	memset(tmp1, 0, sizeof(char)*100);
                        memset(tmp3, 0, sizeof(char)*100);
			pop_from_stack(&arith, tmp1);
			sprintf(tmp3, "( %s )", tmp1);
			push_to_stack(&arith, tmp3); 
		    }
    | '-' arithmetc_expr %prec UMINUS {   memset(tmp1, 0, sizeof(char)*100);
				memset(tmp3, 0, sizeof(char)*100);
				pop_from_stack(&arith, tmp1);
				sprintf(tmp3, " -%s ", tmp1);
				push_to_stack(&arith, tmp3);
			    }
    | CONSTANT	{   memset(tmp3, 0, sizeof(char)*100);
		    sprintf(tmp3, "%s", yylval);
		    push_to_stack(&arith, tmp3);
		}
    | variable  {	memset(tmp1, 0, sizeof(char)*100);
			memset(tmp3, 0, sizeof(char)*100);
			pop_from_stack(&var, tmp1);
			sprintf(tmp3, "%s", tmp1);
			push_to_stack(&arith, tmp3);
		}
    ;
variable    : IDENTIFIER    {	memset(tmp3, 0, sizeof(char)*100);
			sprintf(tmp3, "%s", yylval);
			push_to_stack(&var, tmp3);
		    }

	    | variable '[' arithmetc_expr ']' {   memset(tmp1, 0, sizeof(char)*100);
					memset(tmp2, 0, sizeof(char)*100);
					memset(tmp3, 0, sizeof(char)*100);
					pop_from_stack(&arith, tmp1);
					pop_from_stack(&var, tmp2);
					sprintf(tmp3, "%s[%s]", tmp2, tmp1);
					push_to_stack(&var, tmp3);
				    }

	    | variable '(' ')'  {   memset(tmp3, 0, sizeof(char)*100);
				    memset(tmp1, 0, sizeof(char)*100);
				    pop_from_stack(&var, tmp1);
				    sprintf(tmp3, "%s()", tmp1);
				    push_to_stack(&var, tmp3);
				}

%%


int yywrap(void){
    return 0;
}
void yyerror(char const *s){
    fprintf(stderr, "%s\n", s);
}
int main(void){
    init_stack(&arith);
    init_stack(&var);
    init_stack(&assign);
    yyparse();
    return 0;
}

